package com.dituhui.tool.gis;

/**
 * GPS坐标转换
 * 
 * @author liweigu
 * 
 */
public class CoordConverter {
	private static final double CUSTOM_PI = 3.14159265358979324 * 3000.0 / 180.0;
	/**
	 * 1公里距离的GCJ02经纬度差值，是近似值。
	 */
	public static double GPS_DELTA_PER_KM = 0.008983152841196329;

	/**
	 * 摩卡托坐标转GCJ02经纬度坐标
	 * 
	 * @param point 摩卡托坐标点
	 * @return GCJ02经纬度坐标点
	 */
	public static Point mercatorToLngLat(Point point) {
		// 拷贝对象，避免源对象的属性被修改
		Point newPoint = new Point();
		// 摩卡托坐标转经纬度坐标
		newPoint.setX(mercatorToLng(point.getX()));
		newPoint.setY(mercatorToLat(point.getY()));
		return newPoint;
	}

	/**
	 * GCJ02经纬度坐标转摩卡托坐标
	 * 
	 * @param point GCJ02经纬度坐标点
	 * @return 摩卡托坐标点
	 */
	public static Point lngLatToMercator(Point point) {
		// 拷贝对象，避免源对象的属性被修改
		Point newPoint = new Point();
		// 经纬度坐标转摩卡托坐标
		newPoint.setX(lngToMercator(point.getX()));
		newPoint.setY(latToMercator(point.getY()));
		// 取值并返回
		return new Point(newPoint.getX(), newPoint.getY());
	}

	/**
	 * GCJ02经纬度坐标转百度经纬度坐标
	 * 
	 * @param gcj02GPSPoint GCJ02经纬度坐标点
	 * @return 百度经纬度坐标点
	 */
	public static Point lngLatToBaidu(Point gcj02GPSPoint) {
		Point resultPoint = null;
		if (null != gcj02GPSPoint) {
			double x = gcj02GPSPoint.getX();
			double y = gcj02GPSPoint.getY();
			double z = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)) + 0.00002 * Math.sin(y * CUSTOM_PI);
			double theta = Math.atan2(y, x) + 0.000003 * Math.cos(x * CUSTOM_PI);
			double resultX = z * Math.cos(theta) + 0.0065;
			double resultY = z * Math.sin(theta) + 0.006;
			resultPoint = new Point(resultX, resultY);
		}
		return resultPoint;
	}

	/**
	 * 百度经纬度坐标转GCJ02经纬度坐标
	 * 
	 * @param baiduGPSPoint 百度经纬度坐标点
	 * @return GCJ02经纬度坐标点
	 */
	public static Point baiduToLngLat(Point baiduGPSPoint) {
		Point resultPoint = null;
		if (null != baiduGPSPoint && baiduGPSPoint.getX() > 0 && baiduGPSPoint.getY() > 0) {
			double lon_x = baiduGPSPoint.getX() - 0.0065;
			double lat_y = baiduGPSPoint.getY() - 0.006;
			double z = Math.sqrt(Math.pow(lon_x, 2) + Math.pow(lat_y, 2)) - 0.00002 * Math.sin(lat_y * CUSTOM_PI);
			double theta = Math.atan2(lat_y, lon_x) - 0.000003 * Math.cos(lon_x * CUSTOM_PI);

			double resultX = z * Math.cos(theta);
			double resultY = z * Math.sin(theta);
			resultPoint = new Point(resultX, resultY);
		}
		return resultPoint;
	}

	// private static com.utils.Point adjustedGPS2RealGPS(com.utils.Point adjustedGPSPoint) {
	// // 用二分法反算
	// com.utils.Point tempPoint = CoordinatesConvert.gps2LL(adjustedGPSPoint);
	// double realGPSLon = adjustedGPSPoint.getLon() + (adjustedGPSPoint.getLon() - tempPoint.getLon());
	// double realGPSLat = adjustedGPSPoint.getLat() + (adjustedGPSPoint.getLat() - tempPoint.getLat());
	// com.utils.Point realGPSPoint = new com.utils.Point(realGPSLon, realGPSLat);
	// return realGPSPoint;
	// }

	// // 真实经纬度转百度经纬度
	// private static com.supermap.entity.Point realGPSPoint2BaiduGPS(com.supermap.entity.Point realGPSPoint) {
	// String[] arr = com.supermap.convert.impl.BaiduCoordinateConvertImpl.bdWebAPI(realGPSPoint, 1, 5);
	// double x = Double.parseDouble(arr[0]);
	// double y = Double.parseDouble(arr[1]);
	// com.supermap.entity.Point baiduGPSPoint = new com.supermap.entity.Point(x, y);
	// return baiduGPSPoint;
	// }

	// private static com.supermap.entity.Point baiduGPSPoint2RealGPS(com.supermap.entity.Point baiduGPSPoint) {
	// // 用二分法反算
	// String[] arr = com.supermap.convert.impl.BaiduCoordinateConvertImpl.bdWebAPI(baiduGPSPoint, 1, 5);
	// double x = Double.parseDouble(arr[0]);
	// double y = Double.parseDouble(arr[1]);
	// com.supermap.entity.Point tempGPSPoint = new com.supermap.entity.Point(x, y);
	// double realGPSLon = baiduGPSPoint.getLon() + (baiduGPSPoint.getLon() - tempGPSPoint.getLon());
	// double realGPSLat = baiduGPSPoint.getLat() + (baiduGPSPoint.getLat() - tempGPSPoint.getLat());
	// com.supermap.entity.Point realGPSPoint = new com.supermap.entity.Point(realGPSLon, realGPSLat);
	// return realGPSPoint;
	// }

	private static double lngToMercator(double x) {
		double mx = x / 180.0D * 2.0037508342789244E7D;
		return mx;
	}

	private static double latToMercator(double y) {
		double my = Math.log(Math.tan((90.0D + y) * 3.141592653589793D / 360.0D)) / 0.017453292519943295D;
		my = my / 180.0D * 2.0037508342789244E7D;
		return my;
	}

	private static double mercatorToLng(double x) {
		x = x / 2.0037508342789244E7D * 180.0D;
		return x;
	}

	private static double mercatorToLat(double y) {
		y = y / 2.0037508342789244E7D * 180.0D;
		y = 57.29577951308232D * (2.0D * Math.atan(Math.exp(y * 3.141592653589793D / 180.0D)) - 1.5707963267948966D);
		return y;
	}
}
